﻿using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Threading;
using System.Windows.Forms;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using Color = System.Drawing.Color;

namespace Keithley_2400
{
    public partial class FormMain : Form
    {
        public Keithley keithley = new Keithley();
        private Thread ShowInformationLoopThread = null;
        private Thread ContinueTestLoopThread = null;
        int showInformationLoop_flag = 0;// 0代表不执行循环，1代表执行循环，默认0
        int disconnectKeithley_flag = 0;//0代表不需要ShowInformationLoopThread结束后断开连接，1代表需要ShowInformationLoopThread结束后断开连接，默认0
        int continue_test_flag = 0;//0代表禁用连续输出功能，1代表启用连续输出功能，默认0
        int FormClose_permission = 0;//0代表其他线程未运行完，不可以关闭窗口，1代表其他线程运行完可以关闭窗口
        string ExcelSaveFoldPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);// 默认保存路径为桌面
        public FormMain()
        {
            InitializeComponent();
        }
        // 根据说明书，Keithley2400有以下量程。实际上，根据测试，Keithley2400的电压设置范围是0.2mV-210V，电流设置范围是0.001μA-1.05A
        List<string> VOLTrange = new List<string>// 电压的量程
        {
            "200mV","2V","20V","200V"
        };

        List<string> CURRrange = new List<string>// 电流的量程
        {
            "1μA", "10μA","100μA","1mA","10mA","100mA","1A"
        };
        List<string> VOLTMeasureCmpUnit = new List<string>// 限电压的单位
        {
            "mV", "V"
        };

        List<string> CURRMeasureCmpUnit = new List<string>// 限电流的单位
        {
            "μA", "mA", "A"
        };
        private void SetSourceRange(int source_mode)// 设置恒压模式或恒流模式下的输出量程选项的函数
        {           
            if (source_mode == 0)// 恒压模式
            {
                cbx_SourceRange.Items.Clear();
                cbx_SourceRange.Items.AddRange(VOLTrange.ToArray());// 把电压的量程选项导入
                cbx_MeasureCmpUnit.Items.Clear();
                cbx_MeasureCmpUnit.Items.AddRange(CURRMeasureCmpUnit.ToArray());// 把限电流的单位导入
                label_SetMeasureCmp.Text = "测量限电流：";
            }
            else if(source_mode == 1)
            {
                cbx_SourceRange.Items.Clear();
                cbx_SourceRange.Items.AddRange(CURRrange.ToArray());// 把电流的量程选项导入
                cbx_MeasureCmpUnit.Items.Clear();
                cbx_MeasureCmpUnit.Items.AddRange(VOLTMeasureCmpUnit.ToArray());// 把限电压的单位导入
                label_SetMeasureCmp.Text = "测量限电压：";
            }
            cbx_SourceRange.SelectedIndex = 0;// 默认输出量程10mV(10μA)            
            tbx_SourceLevelValue.Text = "0";// 默认输出电压(流)的值为0
            cbx_MeasureCmpUnit.SelectedIndex = 0;// 默认限电压(流)的单位是mV(μA)
            tbx_MeasureCmpValue.Text = "1";// 默认限电压(流)的值是1
        }
        private void UpdatePorts()
        {
            string[] ports = SerialPort.GetPortNames();// 找到所有可用的端口
            for (int i = 0; i < ports.Length; i++)
            {
                string port = ports[i];
                cbx_portName.Items.Clear();
                cbx_portName.Items.Add(port);
            }
            if (cbx_portName.Items.Count > 0)// 如果有可用端口，则设第一个为默认端口
                cbx_portName.SelectedIndex = 0;
        }
        private void InitializeLabelInformation()// 初始化电压/电流信息
        {
            label_Information.Text = "当前电压/电流\n\n" + "  电压：/\n\n" + "  电流：/";
        }
        private void Initialize_dataGridView()// 初始化dataGridView
        {
            // 设置 DataGridView 的列数
            dataGridView_TestResult.ColumnCount = 2;
            // 设置 DataGridView 的行数，初始化为16行
            dataGridView_TestResult.RowCount = 16;
            dataGridView_TestResult.Columns[0].HeaderText = "测试项目1：V";
            dataGridView_TestResult.Columns[1].HeaderText = "测试项目2：I";
            for (int i = 0; i < 15; i++)
            {
                dataGridView_TestResult.Rows[i].HeaderCell.Value = $"{i + 1}";
            }
        }
        private void Initialize_gb_Test()
        {
            tlssLabel_IsContinueTest.Text = "   ";
            gb_Test.Enabled = false;
            btn_Output.BackColor = Color.Gray;
            btn_StopOutput.BackColor = Color.Gray;
            btn_ContiTest.BackColor = Color.Gray;
            btn_ContiTest.Text = "连续测试";
            InitializeLabelInformation();
            cbx_SourceMode.SelectedIndex = 1;// 默认恒流模式            
            SetSourceRange(cbx_SourceMode.SelectedIndex);
            label_ExcelSavePath.Text = "保存路径：" + ExcelSaveFoldPath;// 默认保存至桌面
        }
        private void FormMain_Load(object sender, EventArgs e)// 打开主窗口时的初始设置
        {         
            UpdatePorts();
            cbx_baudRate.SelectedIndex = 4;// 默认波特率9600
            cbx_parity.SelectedIndex = 0;// 默认奇偶校验位None
            cbx_dataBits.SelectedIndex = 3;// 默认数据位8
            cbx_stopBits.SelectedIndex = 1;// 默认停止位One
            btn_DisconnectKeithley.Enabled = false;

            Initialize_gb_Test();   
            Initialize_dataGridView();
        }
        private void btn_ConnectKeithley_Click(object sender, EventArgs e)// 连接Keithley
        {
            int ret = 0;
            ret = keithley.Connect(cbx_portName.Text, cbx_baudRate.SelectedIndex, cbx_parity.SelectedIndex, cbx_dataBits.SelectedIndex, cbx_stopBits.SelectedIndex);// 1表示连接成功，取得串口通信；0表示连接失败
            if (ret == 1)
            {
                btn_ConnectKeithley.Enabled = false;
                btn_DisconnectKeithley.Enabled = true;

                gb_Test.Enabled = true;
                btn_StopOutput.Enabled = false;

                tlssLabel_IsConnect.Text = "已连接Keithley";
                tlssLabel_IsConnect.ForeColor = Color.Green;
                tlssLabel_IsOutput.Text = "Keithley未在输出";
                tlssLabel_IsOutput.ForeColor = Color.Red;
                // 将当前值写入，初始化源表参数
                SaveParameters();
                cbx_portName.Enabled = false;
                cbx_baudRate.Enabled = false;
                cbx_parity.Enabled = false;
                cbx_dataBits.Enabled = false;
                cbx_stopBits.Enabled = false;

                disconnectKeithley_flag = 0;// 不需要等ShowInformationLoopThread结束后才断开连接
                FormClose_permission = 0;
            }
        }
        private void DisconnectKeithley()// 断开Keithley
        {
            int ret = 0;
            ret = keithley.Disconnect();// 1表示断开成功，断开串口通信；0表示断开失败
            if (ret == 1)
            {
                btn_ConnectKeithley.Enabled = true;
                btn_DisconnectKeithley.Enabled = false;

                Initialize_gb_Test();

                tlssLabel_IsConnect.Text = "未连接Keithley";
                tlssLabel_IsConnect.ForeColor = Color.Red;
                tlssLabel_IsOutput.Text = "   ";
                tlssLabel_IsOutput.ForeColor = Color.Red;
                cbx_portName.Enabled = true;
                cbx_baudRate.Enabled = true;
                cbx_parity.Enabled = true;
                cbx_dataBits.Enabled = true;
                cbx_stopBits.Enabled = true;
                UpdatePorts();
            }
        }
        private void btn_DisconnectKeithley_Click(object sender, EventArgs e)
        {
            if (disconnectKeithley_flag == 0)
                DisconnectKeithley();
            else
                disconnectKeithley_flag = 1;//需要ShowInformationLoopThread结束后断开吉时利

            if (continue_test_flag == 1)// 停止连续测试后停止输出
                continue_test_flag = 0;
            else
                showInformationLoop_flag = 0;// 停止输出                       
        }
        private void SaveParameters()// 保存参数
        {
            keithley.SaveParameters(cbx_SourceMode.SelectedIndex, cbx_SourceRange.Text, tbx_SourceLevelValue.Text, tbx_MeasureCmpValue.Text, cbx_MeasureCmpUnit.SelectedIndex);
        }
        private void btn_SaveParameters_Click(object sender, EventArgs e)
        {
            SaveParameters();
        }
        private void cbx_SourceMode_SelectedIndexChanged(object sender, EventArgs e)
        {
            SetSourceRange(cbx_SourceMode.SelectedIndex);
        }
        private void cbx_SourceRange_SelectedIndexChanged(object sender, EventArgs e)
        {
            string level_unit = keithley.GetRangeUnit(cbx_SourceRange.Text);// 根据选择的量程得到输出单位
            label_SourceLevelUnit.Text = level_unit;
        }
        private void btn_Output_Click(object sender, EventArgs e)
        {
            int ret = 0;
            ret = keithley.Output();// 1表示打开输出成功，0表示打开输出失败
            if(ret == 1)
            {
                btn_Output.Enabled = false;
                btn_StopOutput.Enabled = true;
                tlssLabel_IsOutput.Text = "Keithley正在输出";
                tlssLabel_IsOutput.ForeColor = Color.Green;
                btn_Output.BackColor = Color.Green;
                btn_StopOutput.BackColor = Color.Gray;
                btn_SaveParameters.Enabled = false;
                btn_ManualTest.Enabled = false;// 手动测试禁用
                btn_ContiTest.Enabled = false;// 连续测试禁用

                disconnectKeithley_flag = 1;
                showInformationLoop_flag = 1;
                if (ShowInformationLoopThread == null || !ShowInformationLoopThread.IsAlive)
                {
                    ShowInformationLoopThread = new Thread(ShowInformationLoop);
                    ShowInformationLoopThread.Start();
                }
            }
        }
        private void btn_StopOutput_Click(object sender, EventArgs e)
        {
            showInformationLoop_flag = 0;
            disconnectKeithley_flag = 0;
        }
        private void ShowInformationLoop()// 实时显示电压/电流信息，以及输出时和连续测试时的停止输出和断开连接控制
        {
            int ret = 0;
            while (true)
            {
                if (showInformationLoop_flag == 1)
                {
                    string show_V = GetShowVorI(0);
                    string show_I = GetShowVorI(1);                   
                    label_Information.Invoke(new Action(() =>// 委托主线程执行
                    {
                        label_Information.Text = "当前电压/电流\n\n" + "  电压：" + show_V + "\n\n" + "  电流：" + show_I;
                    }));                        
                }
                else
                {
                    label_Information.Invoke(new Action(() =>// 委托主线程执行
                    {
                        InitializeLabelInformation();
                    }));
                    ret = keithley.StopOutput();// 1表示关闭输出成功，0表示关闭输出失败
                    if (ret == 1)
                    {
                        btn_Output.Invoke(new Action(() =>// 这些控件的控制线程是同一个
                        {
                            btn_Output.Enabled = true;
                            btn_StopOutput.Enabled = false;
                            tlssLabel_IsOutput.Text = "Keithley未在输出";
                            tlssLabel_IsOutput.ForeColor = Color.Red;
                            btn_Output.BackColor = Color.Gray;
                            btn_StopOutput.BackColor = Color.Red;
                            btn_SaveParameters.Enabled = true;
                            btn_ContiTest.Enabled = true;// 启用连续测试按钮
                            btn_ManualTest.Enabled = true;// 启用手动测试按钮
                        }));                                               
                    }
                    if(disconnectKeithley_flag == 1)
                        Invoke((Action)DisconnectKeithley);// 委托主线程执行DisconnectKeithley()
                    break;
                }               
            }
            FormClose_permission = 1;
        }       
        private void FormMain_FormClosing(object sender, FormClosingEventArgs e)// 停止输出，断开连接
        {
            if (btn_DisconnectKeithley.Enabled == true)
            {
                if (disconnectKeithley_flag == 0)
                    DisconnectKeithley();
                else
                    disconnectKeithley_flag = 1;//需要ShowInformationLoopThread结束后断开吉时利

                if (continue_test_flag == 1)// 停止连续测试后停止输出
                    continue_test_flag = 0;
                else
                    showInformationLoop_flag = 0;// 停止输出
                // 等待两个线程是否执行完，再关闭窗体
                if (FormClose_permission == 0)
                {
                    e.Cancel = true;// 取消关闭窗口
                    MessageBox.Show("正在为您断开连接，请稍后关闭！");
                }
            }
        }
        private string GetShowVorI(int VorI_flag)// 根据单位转换显示数值
        {
            string show_VorI = null;
            string information = null;
            Invoke(new Action(() =>// 委托主线程执行,防止另外的线程调用时串口读取冲突
            {
                information = keithley.GetData();
            }));
            // 根据编程手册，将数据按照逗号分割，并存储到对应的字符串变量中
            string[] information_parts = information.Split(',');
            string V = information_parts[0];
            string I = information_parts[1];
            //string R = information_parts[2];
            //string timestamp = information_parts[3];// 时间戳
            //string status_word = information_parts[4];// 状态字
            double V_value = double.Parse(V);// 单位是V
            double I_value = double.Parse(I);// 单位是A
            // 根据单位转换显示数值
            Invoke(new Action(() =>// 委托主线程执行
            {
                if (label_SourceLevelUnit.Text == "V" || label_SourceLevelUnit.Text == "mV")// 恒压输出，测试电流
                {
                    if (label_SourceLevelUnit.Text == "V")
                    {
                        V = V_value.ToString() + " V";
                    }
                    if (label_SourceLevelUnit.Text == "mV")
                    {
                        V_value = V_value * 1e3;
                        V = V_value.ToString() + " mV";
                    }
                    if (cbx_MeasureCmpUnit.Text == "μA")
                    {
                        I_value = I_value * 1e6;
                        I = I_value.ToString() + " μA";
                    }
                    if (cbx_MeasureCmpUnit.Text == "mA")
                    {
                        I_value = I_value * 1e3;
                        I = I_value.ToString() + " mA";
                    }
                }
                else// 恒流输出，测试电压
                {
                    if (label_SourceLevelUnit.Text == "μA")
                    {
                        I_value = I_value * 1e6;
                        I = I_value.ToString() + " μA";
                    }
                    if (label_SourceLevelUnit.Text == "mA")
                    {
                        I_value = I_value * 1e3;
                        I = I_value.ToString() + " mA";
                    }
                    if (cbx_MeasureCmpUnit.Text == "mV")
                    {
                        V_value = V_value * 1e3;
                        V = V_value.ToString() + " mV";
                    }
                    if (cbx_MeasureCmpUnit.Text == "V")
                    {
                        V = V_value.ToString() + " V";
                    }
                }
            }));            
            if (VorI_flag == 0)// 0代表返回显示电压
                show_VorI = V;
            else// 1代表返回显示电流
                show_VorI = I;
            return show_VorI;
        }
        private void btn_ManualTest_Click(object sender, EventArgs e)
        {
            // 打开输出
            int ret_output = 0;
            ret_output = keithley.Output();// 1表示打开输出成功，0表示打开输出失败
            if(ret_output == 1)// 获取数据并记录
            {
                string show_V = GetShowVorI(0);
                string show_I = GetShowVorI(1);
                int num_empty = 0;
                for (int i = 0; i < 15; i++)// 检查空格位
                {
                    if (dataGridView_TestResult.Rows[i].Cells[0].Value == null) { num_empty++; }
                }
                // 将显示数值写入空格
                if (num_empty >= 1)
                {
                    for (int i = 0; i < 15; i++)
                    {
                        if (dataGridView_TestResult.Rows[i].Cells[0].Value == null) 
                        { 
                            dataGridView_TestResult.Rows[i].Cells[0].Value = show_V; 
                            dataGridView_TestResult.Rows[i].Cells[1].Value = show_I; 
                            break; 
                        }
                    }
                }
                else
                {
                    int rowIndex = dataGridView_TestResult.Rows.Add(); // 向 DataGridView 添加一行，并获取新行的索引
                    DataGridViewRow newRow = dataGridView_TestResult.Rows[rowIndex]; // 获取新添加的行
                    newRow.Cells[0].Value = show_V;
                    newRow.Cells[1].Value = show_I;
                    newRow.HeaderCell.Value = $"{dataGridView_TestResult.RowCount - 1}";
                }
            }
            // 关闭输出
            int ret_stop_output = 0;
            ret_stop_output = keithley.StopOutput();// 1表示关闭输出成功，0表示关闭输出失败
        }
        private void ContinueTestLoop()
        {
            while (true)
            {
                if (continue_test_flag == 1)
                {
                    string show_V = GetShowVorI(0);
                    string show_I = GetShowVorI(1);
                    int num_empty = 0;
                    for (int i = 0; i < 15; i++)// 检查空格位
                    {
                        if (dataGridView_TestResult.Rows[i].Cells[0].Value == null) { num_empty++; }
                    }
                    // 将显示数值写入空格
                    if (num_empty >= 1)
                    {
                        for (int i = 0; i < 15; i++)
                        {
                            if (dataGridView_TestResult.Rows[i].Cells[0].Value == null)
                            {
                                dataGridView_TestResult.Rows[i].Cells[0].Value = show_V;
                                dataGridView_TestResult.Rows[i].Cells[1].Value = show_I;
                                break;
                            }
                        }
                    }
                    else
                    {
                        Invoke(new Action(() =>// 委托主线程执行
                        {
                            int rowIndex = dataGridView_TestResult.Rows.Add(); // 向 DataGridView 添加一行，并获取新行的索引
                            DataGridViewRow newRow = dataGridView_TestResult.Rows[rowIndex]; // 获取新添加的行
                            newRow.Cells[0].Value = show_V;
                            newRow.Cells[1].Value = show_I;
                            newRow.HeaderCell.Value = $"{dataGridView_TestResult.RowCount - 1}";
                        }));                       
                    }
                    Thread.Sleep(int.Parse(tbx_TestContiTimeValue.Text));
                }
                else
                {
                    showInformationLoop_flag = 0;
                    break;
                }
            }
        }
        private void btn_ContiTest_Click(object sender, EventArgs e)
        {
            if(btn_ContiTest.Text == "连续测试")// 开启连续测试
            {
                // 打开输出
                int ret = 0;
                ret = keithley.Output();// 1表示打开输出成功，0表示打开输出失败
                if (ret == 1)
                {
                    btn_Output.Enabled = false;// 禁用输出按钮
                    btn_StopOutput.Enabled = false;// 禁用停止输出按钮

                    tlssLabel_IsOutput.Text = "Keithley正在输出";
                    tlssLabel_IsOutput.ForeColor = Color.Green;
                    btn_Output.BackColor = Color.Green;
                    btn_StopOutput.BackColor = Color.Gray;
                    btn_SaveParameters.Enabled = false;
                    btn_ManualTest.Enabled = false;// 手动测试禁用
                    btn_ContiTest.Text = "停止测试";
                    btn_ContiTest.BackColor = Color.Green;
                    tlssLabel_IsContinueTest.Text = "正在进行连续测试";
                    btn_ExportExcel.Enabled = false;
                    btn_ClearTestResult.Enabled = false;

                    disconnectKeithley_flag = 1;// 需要ShowInformationLoopThread断开连接
                    showInformationLoop_flag = 1;

                    if (ShowInformationLoopThread == null || !ShowInformationLoopThread.IsAlive)
                    {
                        ShowInformationLoopThread = new Thread(ShowInformationLoop);
                        ShowInformationLoopThread.Start();
                    }
                    continue_test_flag = 1;
                    if (ContinueTestLoopThread == null || !ContinueTestLoopThread.IsAlive)
                    {
                        ContinueTestLoopThread = new Thread(ContinueTestLoop);
                        ContinueTestLoopThread.Start();
                    }
                }
            }
            else// 关闭连续测试
            {
                continue_test_flag = 0;
                disconnectKeithley_flag = 0;
                showInformationLoop_flag = 0;

                btn_ContiTest.Text = "连续测试";
                btn_ContiTest.BackColor = Color.Gray;
                tlssLabel_IsContinueTest.Text = "   ";
                btn_ExportExcel.Enabled = true;
                btn_ClearTestResult.Enabled = true;
            }
        }
        private void btn_SetExcelSavePath_Click(object sender, EventArgs e)// 更改保存路径
        {
            FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();
            if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
            {
                ExcelSaveFoldPath = folderBrowserDialog.SelectedPath;
                label_ExcelSavePath.Text = "保存路径：" + folderBrowserDialog.SelectedPath;
            }
        }
        private Cell CreateTextCell(string text)
        {
            Cell cell = new Cell(new InlineString(new Text(text)));
            cell.DataType = CellValues.InlineString;
            return cell;
        }
        private void btn_ExportExcel_Click(object sender, EventArgs e)// 导出Excel文件
        {
            string ExcelSavePath = ExcelSaveFoldPath + "\\" + DateTime.Now.ToString("yyyy.MM.dd_HH.mm.ss") + "_test.xlsx";
            using (SpreadsheetDocument document = SpreadsheetDocument.Create(ExcelSavePath, SpreadsheetDocumentType.Workbook))
            {
                WorkbookPart workbookPart = document.AddWorkbookPart();
                workbookPart.Workbook = new Workbook();

                WorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
                worksheetPart.Worksheet = new Worksheet(new SheetData());

                Sheets sheets = document.WorkbookPart.Workbook.AppendChild(new Sheets());
                Sheet sheet = new Sheet()
                {
                    Id = document.WorkbookPart.GetIdOfPart(worksheetPart),
                    SheetId = 1,
                    Name = "Sheet1"
                };
                sheets.Append(sheet);

                // 获取列标题
                Row headerRow = new Row();
                foreach (DataGridViewColumn column in dataGridView_TestResult.Columns)
                {
                    headerRow.AppendChild(CreateTextCell(column.HeaderText));
                }

                SheetData sheetData = worksheetPart.Worksheet.GetFirstChild<SheetData>();
                sheetData.AppendChild(headerRow);

                // 添加行数据
                foreach (DataGridViewRow row in dataGridView_TestResult.Rows)
                {
                    Row newRow = new Row();
                    foreach (DataGridViewCell cell in row.Cells)
                    {
                        newRow.AppendChild(CreateTextCell(cell.Value?.ToString() ?? ""));
                    }
                    sheetData.AppendChild(newRow);
                }
            }
        }
        private void btn_ClearTestResult_Click(object sender, EventArgs e)// 清空dataGridView
        {
            dataGridView_TestResult.Rows.Clear();
            Initialize_dataGridView();
        } 
    }
}
